package com.zq.sdklib.transform.cost.javassist

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import javassist.CannotCompileException
import javassist.NotFoundException
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
import java.io.File

class MethodCostTransform : Transform {

    var project:Project

    constructor(project: Project) : super(){
        this.project = project
    }

    override fun getName(): String {
        return this::class.java.simpleName
    }

    override fun getInputTypes(): MutableSet<QualifiedContent.ContentType> {
        return TransformManager.CONTENT_CLASS
    }

    override fun getScopes(): MutableSet<in QualifiedContent.Scope> {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    override fun isIncremental(): Boolean {
        return true
    }

    override fun transform(transformInvocation: TransformInvocation) {
        super.transform(transformInvocation)
        val isIncremental = transformInvocation.isIncremental && this.isIncremental
        println("---- $name start ---- ${if(isIncremental) "增量" else "非增量"}")
        if (!isIncremental) {
            //不需要增量编译，先清除全部
            transformInvocation.outputProvider.deleteAll()
        }
        transformInvocation.inputs.forEach { transformInput ->
            transformInput.directoryInputs.forEach { directoryInput ->
                //处理文件
                processDirectoryInputWithIncremental(directoryInput, transformInvocation.outputProvider, isIncremental)
            }
            transformInput.jarInputs.forEach { jarInput ->
                //处理Jar
                processJarInputWithIncremental(jarInput, transformInvocation.outputProvider, isIncremental)
            }
        }
        println("---- $name end ----")
    }


    private fun processDirectoryInputWithIncremental(directoryInput: DirectoryInput, outputProvider: TransformOutputProvider, isIncremental:Boolean) {
        val dest = outputProvider.getContentLocation(
            directoryInput.name,
            directoryInput.contentTypes,
            directoryInput.scopes,
            Format.DIRECTORY
        )
        if (isIncremental) {
            //处理增量编译
            processDirectoryInputWhenIncremental(directoryInput, dest)
        } else {
            processDirectoryInput(directoryInput, dest)
        }
    }

    fun processDirectoryInputWhenIncremental(directoryInput:DirectoryInput , dest: File) {
        FileUtils.forceMkdir(dest)
        val srcDirPath = directoryInput.file.absolutePath
        val destDirPath = dest.absolutePath
        val fileStatusMap = directoryInput.changedFiles
        fileStatusMap.forEach { entry ->
            val inputFile = entry.key
            val status = entry.value
            val destFilePath = inputFile.absolutePath.replace(srcDirPath, destDirPath)
            val destFile = File(destFilePath)
            when (status) {
                Status.NOTCHANGED -> {}
                Status.REMOVED -> {
                    if (destFile.exists()) {
                        FileUtils.forceDelete(destFile)
                    }
                }
                Status.ADDED, Status.CHANGED -> {
                    FileUtils.touch(destFile)
                    transformSingleFile(inputFile, destFile, srcDirPath)
                }
            }
        }
    }

    fun processDirectoryInput(directoryInput:DirectoryInput , dest: File) {
        transformDirectoryInput(directoryInput, dest)
    }

    fun transformDirectoryInput(directoryInput:DirectoryInput , dest: File) {
        //TODO do some transform
        println("transformDirectoryInput directoryInput=" + directoryInput.name)
        try {
            InjectUtil.injectCostForDir(
                directoryInput.file,
                project
            )
        } catch (e: NotFoundException) {
            e.printStackTrace()
        } catch (e: CannotCompileException) {
            e.printStackTrace()
        }
        //将修改过的字节码copy到dest，就可以实现编译期间干预字节码的目的了
        println("${directoryInput.getFile()} \n=> $dest")
        FileUtils.copyDirectory(directoryInput.getFile(), dest)
    }

    fun transformSingleFile(inputFile: File, destFile: File, srcDirPath:String) {
        //TODO do some transform
        println("transformSingleFile inputFile = $inputFile")
        try {
            InjectUtil.injectCostForFile(
                File(srcDirPath),
                inputFile,
                project
            )
        } catch (e: NotFoundException) {
            e.printStackTrace()
        } catch (e: CannotCompileException) {
            e.printStackTrace()
        }
        println("$inputFile \n=> $destFile")
        FileUtils.copyFile(inputFile, destFile)
    }




    /////------------------------------------

    private fun processJarInputWithIncremental(jarInput:JarInput, outputProvider:TransformOutputProvider,isIncremental:Boolean ) {
        val dest = outputProvider.getContentLocation(
            jarInput.file.absolutePath,
            jarInput.contentTypes,
            jarInput.scopes,
            Format.JAR
        )
        // to do some transform
        if (isIncremental) {
            //处理增量编译
            processJarInputWhenIncremental(jarInput, dest)
        } else {
            //不处理增量编译
            processJarInput(jarInput, dest)
        }
        // 将修改过的字节码copy到dest，就可以实现编译期间干预字节码的目的了
        FileUtils.copyFile(jarInput.file, dest)
    }

    fun processJarInput(jarInput:JarInput , dest: File) {
        transformJarInput(jarInput, dest)
    }

    fun processJarInputWhenIncremental(jarInput:JarInput , dest: File) {
        when (jarInput.status) {
            Status.NOTCHANGED ->{}
            Status.ADDED, Status.CHANGED -> {
                transformJarInputWhenIncremental(jarInput, dest, jarInput.status)
            }
            Status.REMOVED -> {
                //移除Removed
                if (dest.exists()) {
                    FileUtils.forceDelete(dest)
                }
            }
        }
    }

    fun transformJarInputWhenIncremental(jarInput:JarInput, dest: File, status:Status ) {
        if (status == Status.CHANGED) {
            //Changed的状态需要先删除之前的
            if (dest.exists()) {
                FileUtils.forceDelete(dest)
            }
        }
        //真正transform的地方
        transformJarInput(jarInput, dest)
    }

    fun transformJarInput(jarInput:JarInput , dest: File) {
        //TODO do some transform
        println("${jarInput.file} \n=> $dest")
        //将修改过的字节码copy到dest，就可以实现编译期间干预字节码的目的了
        FileUtils.copyFile(jarInput.file, dest)
    }

}